// ========== Copyright Header Begin ==========================================
// 
// OpenSPARC T1 Processor File: Ni_Mmu.cc
// Copyright (c) 2006 Sun Microsystems, Inc.  All Rights Reserved.
// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES.
// 
// The above named program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License version 2 as published by the Free Software Foundation.
// 
// The above named program is distributed in the hope that it will be 
// useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// General Public License for more details.
// 
// You should have received a copy of the GNU General Public
// License along with this work; if not, write to the Free Software
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
// 
// ========== Copyright Header End ============================================
/************************************************************************
**  
**  Copyright (C) 2002, Sun Microsystems, Inc.
**
**  Sun considers its source code as an unpublished, proprietary
**  trade secret and it is available only under strict license provisions.
**  This copyright notice is placed here only to protect Sun in the event 
**  the source is deemed a published work. Disassembly, decompilation,
**  or other means of reducing the object code to human readable form
**  is prohibited by the license agreement under which this code is
**  provided to the user or company in possession of this copy."
**
*************************************************************************/
#include "Ni/Ni_Mmu.h"
#include "TtePos.h"
#include "Ni/Ni_Tte.h"
#include "Ni/Ni_Tlb.h"
#include "StdMacros.h"
#include "InstructionWord.h"
#include "V9/V9_Asi.h"
#include "Gm/Gm_Asi.h"
#include "Ni/Ni_Asi.h"
#include "Sf/Sf_Trap.h"
#include "Ni/Ni_Trap.h"
#include "Sf/Sf_MemdatInitAdapter.h"
#include "MemoryTransaction.h"
#include "Util/StringUtils.h"
#include "Blaze_CBInterface.h"
#include <sstream>
#include "Ni/Ni_Strand.h"

#define RS_INSTR 0x1
#define RS_DATA  0x2

// Gemini physical address expansion for JBUS                                                                         
//  - expand 41-bit PA from the core to a 43-bit (physical JBUS) address                                              
//    memory request                                           JBUS_PA[42:41]                                         
//     cacheable transaction                                    =>  2'b00                                             
//     non-cacheable && (PA[40:36] == CSR) where (CSR == 5'h0)  =>  2'b10                                             
//     non-cacheable && (PA[40:36] != CSR)                      =>  2'b11                                             
#define PA_42_41_MASK    0xfffff9ffFFFFFFFFull                                                                        
#define GEMINI_CSR(pa)   ( (((pa)>>36) & 0x1f)==0 )                                                                   
                                 

using namespace std;
using namespace Riesling;

#define HI_W(lword) (((uint32_t*)&lword)[0])
#define LO_W(lword) (((uint32_t*)&lword)[1]) 

////////////////////////////////////////////////////////////////

Ni_Mmu::Ni_Mmu() :
    cosimDtte_(0),
    cosimItte_(0)
{
    mmuState_ = getNewMmuState();
    rtlITlbMiss = 0;
    rtlDTlbMiss = 0;
    mmuState_->isTsbDirectPointerPs0(true);

    // Construct this here. 
    //dummyTte = Ni_Tte();
}

////////////////////////////////////////////////////////////////

Ni_Mmu::Ni_Mmu( const Ni_Mmu & orig )
{ 
    RIESLING_THROW_DOMAIN_ERROR("Ni_Mmu don't support copy constructor");
}

////////////////////////////////////////////////////////////////

Ni_Mmu::~Ni_Mmu()
{}

////////////////////////////////////////////////////////////////

const Ni_Mmu &
Ni_Mmu::operator=( const Ni_Mmu & rhs )
{
    return *this;
}

////////////////////////////////////////////////////////////////

bool
Ni_Mmu::operator==( const Ni_Mmu & rhs ) const
{ 
    return itlb_ == rhs.itlb_ && dtlb_ == rhs.dtlb_ && hpstate_ == rhs.hpstate_;
}

////////////////////////////////////////////////////////////////

string
Ni_Mmu::toString() const
{
    ostringstream os;

    os << "I TLB: \n";
    os << itlb_->toString();
    os << "\n\\n\nnD TLB: \n";
    os << dtlb_->toString();
    os << "\n\\n\nnmmuState: \n";
    os << mmuState_->toString();
    
    os << "LSU Control Reg:";
    os << "0x" << hex << sharedState_->getLsuControlRegPtr()->getNative() << endl;
    os << sharedState_->getLsuControlRegPtr()->toString();

    return os.str();
}

#define NI_PA_MASK   		0xFFFFFFFFFFULL
#define NI_VA_MASK   		0xFFFFFFFFFFFFULL
#define NI_VA_EXP		47
#define NI_VA_BIT47   		0x0000800000000000ULL
#define NI_VA_HOLE_START        0x0000800000000000ULL
#define NI_VA_HOLE_END          0xFFFF7FFFFFFFFFFFULL

////////////////////////////////////////////////////////////////

bool
Ni_Mmu::vaddrOutOfRange( VaddrT vaddr )
{
    if( (vaddr >= NI_VA_HOLE_START) && (vaddr <= NI_VA_HOLE_END) ) {
        return true;
    } else {
        return false;
    }

}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::instrPreCheck( MemoryTransaction &req )
{
    
}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::instrPostCheck( MemoryTransaction &t, Ni_Tte *tte )
{
    
}


////////////////////////////////////////////////////////////////


void
Ni_Mmu::dataPreCheck( MemoryTransaction &req, int effPriv )
{
    AsiT asi = req.asi();
    AsiObject *asiObj = getAsiObject();
}


////////////////////////////////////////////////////////////////

void
Ni_Mmu::dataPostCheck( MemoryTransaction &t, Ni_Tte *tte, int effPriv )
{
    AsiObject *asiObj = getAsiObject();
    AsiT asi = t.asi();
}

////////////////////////////////////////////////////////////////


void
Ni_Mmu::handleData( MemoryTransaction &xact )
{
    PaddrT paddr;
    TtePos pos;
    uint_t pgSize = 0;
    Ni_Tte *tte = NULL;

    bool internalXact = false;
    VaddrT alignMask = 0;
    VaddrT vaddr;
    //    bool dMmuEnabled;
    bool bypassing;  // true when LSU.DM=0 & HPSTATE.ENB=0

    Uint32T  trapPrio = 9999;			
    Uint32T  trapType  = 0;
    Uint8T   faultType = 0;

    AsiT asi;
    AsiObject *asiObj = getAsiObject();
    bool bypassAsi = false;
    bool quadLddAsi = false;
    bool invalidLdSt = false;

    int priv    = pstate_->getPRIV() | (hpstate_->getHPRIV() != 0);
    int effPriv = priv;

    Uint32T	pid;
    Uint32T	r_bit = 0;

    InstructionWord* iw = xact.getInstructionWordPtr();
    InstructionWord::OpcodeT  opcode = iw->getOpcode();

    if( opcode == InstructionWord::FLUSH ){
	return;
    }

    pid = mmuState_->getidPartitionIdPtr()->getPID();

    tte = NULL;

    asi    = xact.asi();

    PrivModeT privMode = checkPrivMode();

    bypassAsi = checkBypassAsi(privMode, asi);

    // Ni is like Gm and masks VA, PA, and RA when PSTATE.AM == 1
    if (pstate_->getAM())
      xact.vaddr(xact.vaddr() & 0x0ffffffffULL);
    vaddr = xact.vaddr();
    
    bypassing = (!hpstate_->getENB() && !sharedState_->getLsuControlRegPtr()->getDM()) ?
      true : false;

    internalXact = xact.internalXact(); 

    bool asIfUserAsi = false;

							// MMU-7, *BLK_INIT_ST_QUAD_LDD*
    if( asi == Ni_Asi::ASI_AS_IF_USER_PRIMARY ||
	asi == Ni_Asi::ASI_AS_IF_USER_SECONDARY ||
	asi == Ni_Asi::ASI_AS_IF_USER_PRIMARY_LITTLE ||
	asi == Ni_Asi::ASI_AS_IF_USER_SECONDARY_LITTLE ||
	asi == Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_P ||
	asi == Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_S ||
	asi == Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_P_LITTLE ||
	asi == Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_S_LITTLE ||
	asi == Ni_Asi::ASI_BLOCK_AS_IF_USER_PRIMARY ||
	asi == Ni_Asi::ASI_BLOCK_AS_IF_USER_SECONDARY ||
	asi == Ni_Asi::ASI_BLOCK_AS_IF_USER_PRIMARY_LITTLE ||
	asi == Ni_Asi::ASI_BLOCK_AS_IF_USER_SECONDARY_LITTLE )
    {
	effPriv     = 0;
	asIfUserAsi = true;
    }

    r_bit = 0;
    if( asi == 0x14 || asi == 0x15 ||
	asi == 0x1c || asi == 0x1d ||
	asi == 0x26 || asi == 0x2e )
    {
	r_bit = 1;
    }

//     if( (checkPrivMode() == PRIV_SUPER) && (sharedState_->getLsuControlRegPtr()->getDM()==0) ) {
// 	r_bit = 1;
//     }
//     if( (checkPrivMode() == PRIV_USER) && (sharedState_->getLsuControlRegPtr()->getDM()==0) ) {
// 	r_bit = 1;
//     }

    if (hpstate_->getENB() && !sharedState_->getLsuControlRegPtr()->getDM() &&
	(hpstate_->getHPRIV() == 0)) {
      r_bit = 1;
    }

    bool validOpcode = false;

    switch( asi ){
	case Ni_Asi::ASI_NUCLEUS:
	case Ni_Asi::ASI_NUCLEUS_LITTLE:
	case Ni_Asi::ASI_AS_IF_USER_PRIMARY:
	case Ni_Asi::ASI_AS_IF_USER_SECONDARY:
	case Ni_Asi::ASI_AS_IF_USER_PRIMARY_LITTLE:
	case Ni_Asi::ASI_AS_IF_USER_SECONDARY_LITTLE:
	case Ni_Asi::ASI_PRIMARY:
	case Ni_Asi::ASI_SECONDARY:
	case Ni_Asi::ASI_PRIMARY_LITTLE:
	case Ni_Asi::ASI_SECONDARY_LITTLE:
	case Ni_Asi::ASI_REAL_MEM:
	case Ni_Asi::ASI_REAL_MEM_LITTLE:
	{
	    if( iw->isLoad() || iw->isStore() || 
		iw->isAtomic() || iw->isPrefetch() 
	      ){
		validOpcode = true;
	    } 
	}
	break;

	case Ni_Asi::ASI_PRIMARY_NO_FAULT:
	case Ni_Asi::ASI_SECONDARY_NO_FAULT:
	case Ni_Asi::ASI_PRIMARY_NO_FAULT_LITTLE:
	case Ni_Asi::ASI_SECONDARY_NO_FAULT_LITTLE:
	    if( iw->isLoad() || iw->isPrefetch() ){
		validOpcode = true;
	    } 			// Store to NO FAULT ASI's not allowed MMU-17
	    break;              // atomic is also not allowed 2/11/04

	case Ni_Asi::ASI_REAL_IO:			// 12/5/03. 
	case Ni_Asi::ASI_REAL_IO_LITTLE:		// 12/5/03.
	{
	    if( iw->isLoad() || iw->isStore() || iw->isPrefetch() ){
		validOpcode = true;
	    } 
	}
	break;

	case Ni_Asi::ASI_QUAD_LDD:
	case Ni_Asi::ASI_QUAD_LDD_LITTLE:
	case Ni_Asi::ASI_QUAD_LDD_REAL:
	case Ni_Asi::ASI_QUAD_LDD_REAL_LITTLE:
	{
	    quadLddAsi = true;

	    validOpcode = true;

	    if( opcode != InstructionWord::LDDA ) {
	        invalidLdSt = true;
	    }	
	}
	break;

	case Ni_Asi::ASI_NUCLEUS_BLK_INIT_ST_QUAD_LDD:
	case Ni_Asi::ASI_NUCLEUS_BLK_INIT_ST_QUAD_LDD_LITTLE:
	case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_P:
	case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_P_LITTLE:
	case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_S:
	case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_S_LITTLE:
	case Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_P:
	case Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_P_LITTLE:
	case Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_S:
	case Ni_Asi::ASI_AS_IF_USER_BLK_INIT_ST_QUAD_LDD_S_LITTLE:
	{

	    validOpcode = true;

	    if( iw->isLoad() )
	    {
	        quadLddAsi = true;
	    }

            if( (iw->isLoad() && opcode != InstructionWord::LDDA) || 
		iw->isStoreFloat() || 				// MMU-18
		iw->isAtomic()) 
	    {
	        invalidLdSt = true;
            }

	}
	break;


	case Ni_Asi::ASI_BLOCK_AS_IF_USER_PRIMARY:
	case Ni_Asi::ASI_BLOCK_AS_IF_USER_SECONDARY:
	case Ni_Asi::ASI_BLOCK_AS_IF_USER_PRIMARY_LITTLE:
	case Ni_Asi::ASI_BLOCK_AS_IF_USER_SECONDARY_LITTLE:
	case Ni_Asi::ASI_BLK_P:
	case Ni_Asi::ASI_BLK_S:
	case Ni_Asi::ASI_BLK_PL:
	case Ni_Asi::ASI_BLK_SL:
	{
	    switch( opcode ){
		case InstructionWord::LDDFA:
		case InstructionWord::STDFA:
		{
		    validOpcode = true;
		}
		break;
	    }
	}
	break;

	case Ni_Asi::ASI_PST8_P:
        case Ni_Asi::ASI_PST8_S:
        case Ni_Asi::ASI_PST16_P:
        case Ni_Asi::ASI_PST16_S:
        case Ni_Asi::ASI_PST32_P:
        case Ni_Asi::ASI_PST32_S:
        case Ni_Asi::ASI_PST8_PL:
        case Ni_Asi::ASI_PST8_SL:
        case Ni_Asi::ASI_PST16_PL:
        case Ni_Asi::ASI_PST16_SL:
        case Ni_Asi::ASI_PST32_PL:
        case Ni_Asi::ASI_PST32_SL:
        case Ni_Asi::ASI_BLK_COMMIT_P:
        case Ni_Asi::ASI_BLK_COMMIT_S:
	    validOpcode = (opcode == InstructionWord::STDFA);
	    invalidLdSt = true;
	    if(privMode == HYPER)
	        bypassAsi = true;

	break;
        case Ni_Asi::ASI_FL8_P:
        case Ni_Asi::ASI_FL8_S:
        case Ni_Asi::ASI_FL16_P:
        case Ni_Asi::ASI_FL16_S:
        case Ni_Asi::ASI_FL8_PL:
        case Ni_Asi::ASI_FL8_SL:
        case Ni_Asi::ASI_FL16_PL:
        case Ni_Asi::ASI_FL16_SL:
            validOpcode = (opcode == InstructionWord::LDDFA) || (opcode == InstructionWord::STDFA);
	    invalidLdSt = true;
	    if(privMode == HYPER)
	        bypassAsi = true;

	break;


	default:
	{
	    switch( opcode ){
		case InstructionWord::LDXA:
		case InstructionWord::STXA:
		case InstructionWord::LDDFA:
		case InstructionWord::STDFA:
		{
		    validOpcode = true;
		}
		break;
	    }
	    bypassAsi   = ((privMode == HYPER) && asi >= 0x80);
	}
	break;
    }


		// check priority 10 traps, all are alignment related
		// MMU-16

    if( iw->isPrefetch() == false ){
	
        bool inst_LDDF_A = (opcode==InstructionWord::LDDF) ? true :
			       (opcode==InstructionWord::LDDFA) ? true : false;

	bool inst_STDF_A = (opcode==InstructionWord::STDF) ? true :
			       (opcode==InstructionWord::STDFA) ? true : false;

	if( xact.specialAlignment() ){
	    alignMask = xact.getAlignment() - 1;
	} else if( validOpcode ) {
						// if asi is valid for instr, use 
						// xact size for alignment check, 
						// else use alignment as implied by 
						// instruction for alignment check
	    alignMask = xact.size() - 1;
	} else {
	    alignMask = iw->getInstAlignSize() - 1;
	}	

        if( (vaddr & alignMask) != 0 ){

	    bool aligned32Not64 = ((vaddr&0x3 == 0) && (vaddr&0x7 != 0)) ? true : false;
	    // For all BLOCK asi's used with lddfa and stdfa, only a 
	    // mem_addr_not_aligned trap should ever be issued. An 
	    // LDDF_mem_addr_not_aligned or STDF_mem_addr_not_aligned should 
	    // not be issued.
	    if (((opcode == InstructionWord::LDDFA) || (opcode == InstructionWord::STDFA)) && 
		(Ni_Asi::getInstance()->isBlockOp(asi))) {
		trapType  = Ni_Trap::mem_address_not_aligned;
	    }
	    else if( inst_LDDF_A && aligned32Not64 ) {
			// LDDF_mem_address_not_aligned only when vaddr is 32-bit aligned
			// but not 64-bit aligned
	        trapType = Ni_Trap::LDDF_mem_address_not_aligned;	// priority=10
		trapPrio = 10;
            } else if( inst_STDF_A && aligned32Not64 ) {
			// STDF_mem_address_not_aligned only when vaddr is 32-bit aligned
			// but not 64-bit aligned
	        trapType = Ni_Trap::STDF_mem_address_not_aligned;	// priority=10
		trapPrio = 10;
	    } else {
		// for STDF{A}/LDQF{A}, we should probably not get here because they
                // are not supported and cause an illegal_instruction trap in Ni
                // trapType = Ni_Trap::LDQF_mem_address_not_aligned;	// priority=10
                // trapType = Ni_Trap::STQF_mem_address_not_aligned;	// priority=10

	        trapType  = Ni_Trap::mem_address_not_aligned;		// priority=10	
		trapPrio = 10;
	    }
	}

    }

	// if trap is detected, don't take it just yet. wait till
	// we figure out what TTE to use, if any. we need that
	// to decide how to set D-SFSR


		// check priority 11 traps. two types of priority 11 trap can
		// happen in data accesses. they are
		// 	privileged_action
		//	VA_watchpoint
		// among them privileged_action has higher priority than 
		// VA_watchpoint

    //    if( trapPrio>=11 && (iw->isPrefetch() == false) && (priv == 0) && (asi <= 0x7F) ){
    bool accessUseVA = !(bypassing || bypassAsi);
    if( trapPrio>=11 && (priv == 0) && (asi <= 0x7F) ){ // 2/9/04
	trapType  = Ni_Trap::privileged_action;		// priority=11
	trapPrio = 11;
	faultType = 0;					// faultType is non-zero for
							// data_access_exception only
    }
    else if( trapPrio>=11 && accessUseVA && !(privMode == PRIV_HYPER) && !xact.internalXact()){ //2/9/04
	if( checkDataVaWatchpoint( xact )){
	    trapPrio = 11;
	    trapType = Ni_Trap::VA_watchpoint;				// priority=11
	    faultType = 0;					
	}
    }

	// if trap is detected, don't take it just yet. wait till
	// we figure out what TTE to use, if any. we need that
	// to decide how to set D-SFSR


    //    if( trapPrio>=12 && dMmuEnabled ){	//remove dMmuEnabled, 2/9/04
    if( trapPrio>=12 ){	
	if( validOpcode == false ){
	    trapPrio = 12;
	    trapType = Ni_Trap::data_access_exception;			// priority=12
	    faultType |= ILLEGAL_INSTR_VA_ASI;
	} 

	if( (iw->isLoad() || iw->isAtomic()) && !asiObj->readAccess( asi, vaddr ) ){
	    trapPrio = 12;
	    trapType  = Ni_Trap::data_access_exception;			// priority=12
	    faultType |= ILLEGAL_INSTR_VA_ASI;
	}

	if( (iw->isStore() || iw->isAtomic()) && !asiObj->writeAccess( asi, vaddr ) ){
	    trapPrio = 12;
	    trapType  = Ni_Trap::data_access_exception;			// priority=12
	    faultType |= ILLEGAL_INSTR_VA_ASI;
	}

	if( invalidLdSt ) {
	    trapPrio = 12;
	    trapType  = Ni_Trap::data_access_exception;			// priority=12
	    faultType |= ILLEGAL_INSTR_VA_ASI;
	}
 	 
   }

		// check priority 12 traps. Among those that can happen
		// here, data_access_exception has highest priority
		// the other priority 12 traps requires successful TLB
		// look up
    //    if( trapPrio>=12 && (dMmuEnabled==true) && (iw->isPrefetch() == false) && vaddrOutOfRange(vaddr) )
    if(trapPrio>=12 && !bypassing && !bypassAsi && vaddrOutOfRange(vaddr)) { //2/9/04
	if( pstate_->getAM() == 0 ) {					// MMU-19
	    trapPrio = 12;
	    trapType = Ni_Trap::data_access_exception;			// priority=12
	    faultType |= VA_OUT_OF_RANGE;
	}
    }

    if(bypassing || bypassAsi) {

        dummyTte.format4u(true);

        dummyTte.setDataField( Ni_Tte::CP,   0 );
	dummyTte.setDataField( Ni_Tte::IE,   0 );
	dummyTte.setDataField( Ni_Tte::CV,   0 );
	dummyTte.setDataField( Ni_Tte::E,    0 );
	dummyTte.setDataField( Ni_Tte::P,    0 );
	dummyTte.setDataField( Ni_Tte::W,    0 );
	dummyTte.setDataField( Ni_Tte::NFO,  0 );
	dummyTte.setDataField( Ni_Tte::SZL,  0 );
	dummyTte.setDataField( Ni_Tte::SZH,  0 );

        if( asi == Ni_Asi::ASI_REAL_IO || asi == Ni_Asi::ASI_REAL_IO_LITTLE ) 
	{
	    dummyTte.setDataField( Ni_Tte::W,    1 );		// MMU-15
	    dummyTte.setDataField( Ni_Tte::E,    1 );		// MMU-15
	} 
	else if ( asi==Ni_Asi::ASI_REAL_MEM || 
		  asi==Ni_Asi::ASI_REAL_MEM_LITTLE )
	{
	    dummyTte.setDataField( Ni_Tte::W,    1 );
	}
        else if(  asi==Ni_Asi::ASI_QUAD_LDD_REAL || 
		  asi==Ni_Asi::ASI_QUAD_LDD_REAL_LITTLE ) 
	{
	    dummyTte.setDataField( Ni_Tte::W,    1 );
	    if( (vaddr>>39) & 1 ) 
            {
	        dummyTte.setDataField( Ni_Tte::E,    1 );
	        dummyTte.setDataField( Ni_Tte::W,    1 );
	    }
	} 
        else if( (vaddr>>39) & 1 ) 
        {
	    dummyTte.setDataField( Ni_Tte::E,    1 );
	    dummyTte.setDataField( Ni_Tte::W,    1 );
	}
	else
	{
            dummyTte.setDataField( Ni_Tte::CP,   1 );
	    dummyTte.setDataField( Ni_Tte::W,    1 );
	}

        paddr = vaddr & NI_PA_MASK;

        AsiObject *asiObj = getAsiObject();
        ContextT  ctxt;
	if( asiObj->isPrimaryCtxt( asi )){
	    ctxt = mmuState_->getPrimaryDContext();
	} else if( asiObj->isSecondaryCtxt( asi ) ){
	    ctxt = mmuState_->getSecondaryContext();
	} else if( asiObj->isNucleusCtxt( asi ) ){
	    ctxt = 0;
	} else {
	    if( trapType == Ni_Trap::data_access_exception ){
		ctxt = 0; // undefined value
	    }
	} 
	dummyTte.context(ctxt);

        tte = &dummyTte;

    } 
    else if (cosimDtte_ != 0 && !rtlDTlbMiss) {
	// if a dtte is provided by testbench, use that instead of looking
	// for a match in dtlb.
	// also check that there has not been a dmmu miss signal from RTL ... 08/25/2005
	Ni_TteDataSun4u *tteData  = new Ni_TteDataSun4u();
	tteData->setNative( cosimDtte_ );
	// Do not construct here. It becomes a memory leak. 
	//	dummyTte = Ni_Tte(0, 0, tteData, 0, 0);
        dummyTte.format4u(true);

        dummyTte.setDataField( Ni_Tte::CP,   tteData->getCP() );
	dummyTte.setDataField( Ni_Tte::IE,   tteData->getIE() );
	dummyTte.setDataField( Ni_Tte::CV,   tteData->getCV() );
	dummyTte.setDataField( Ni_Tte::E,    tteData->getE() );
	dummyTte.setDataField( Ni_Tte::P,    tteData->getP() );
	dummyTte.setDataField( Ni_Tte::W,    tteData->getW() );
	dummyTte.setDataField( Ni_Tte::NFO,  tteData->getNFO() );
	dummyTte.setDataField( Ni_Tte::SZL,  tteData->getSZL() );
	dummyTte.setDataField( Ni_Tte::SZH,  tteData->getSZH() );

	tte = &dummyTte;
	paddr = tte->translate(vaddr);
	cosimDtte_ = 0;
	delete(tteData);
    }
    else {

	ContextT ctxt = getDCtxt( xact.asi() );

        pos = dtlb_->translate( xact.vaddr(), ctxt, pgSize, paddr, pid, r_bit, internalXact );

	if (BlazeCBInterface::cosim()) {
	  if ( pos.nmatches_ ) {
	    if ( rtlDTlbMiss ) {	// RTL detects MISS but Riesling doesn't 
	      pos.nmatches_ = 0;	// trust RTL and force status to MISS
	    }
	  }
	  else {
	    if ( rtlDTlbMiss==0 ) { 	// Riesling detects MISS but RTL doesn't
					// If RTL has not told us it has caught a TLB miss since
					// the last one, we have probably been hit with that cosim
					// artifact in which the TLB entry was bumped by another 
					// thread. check the victim cache to see if it's there.
					// That's how sas gets arround the problem also.
					// 11/24/03
	      pos = dtlb_->translateUsingVictimTlb( xact.vaddr(), ctxt, pgSize, paddr, pid, r_bit );
	    }
	  }
	  if ( rtlITlbMiss ) {		// RTL detects MISS but Riesling doesn't
	      // Zero cosimDtte_ in case rtlDTlbmiss has been set ... 08/25/2005
	      cosimDtte_ = 0;
	  }

	}

	if( pos.nmatches_ == 0 ){

	    if( !internalXact ) {
                rtlDTlbMiss = 0;
	    }

	    if( iw->isPrefetch() == true )
	        return;

	    if( trapType != 0 ){
		dMmuTrap( xact, trapType, faultType, tte, "dmmu: MMU-miss trap superseded by higher priority trap" );
	    }

	    if( r_bit == 0 )
	    {		
		trapType=Ni_Trap::fast_data_access_MMU_miss;	// priority=12
		faultType = 0;					// faultType is non-zero on for data_access_exception
	        dMmuTrap( xact, trapType, faultType, tte, "dmmu miss." );
	    }
	    else
	    {
		trapType=Ni_Trap::data_real_translation_miss;	// priority=12
		faultType = 0;					// faultType is non-zero on for data_access_exception
	        dMmuTrap( xact, trapType, faultType, tte, "dmmu real miss" );
	    }

	}
	tte = (Ni_Tte*)pos.tte_;
    }

    paddr = getNewPaddr( paddr, tte->data4u().getCP() );
    xact.paddr( paddr );

    if( asiObj->translate( asi ) ){
        if( tte != NULL ){
	    if( asiObj->isLittleEndian( asi ) ^ tte->data4u().getIE() ){
		xact.setReverseByteOrder();
	    }
	}
    }

    if( (iw->isPrefetch() == false) && (trapType != 0) ){
			// here we take the trap detected before we did
			// the tlb look-up above. Now we have a TTE to 
			// work with
			// feb 3, 2004

			// Take traps that are priority 11 and below here.
			// For data_access_exception trap (priority 12)
			// we need to wait to see if we detect other faultTypes
			// that we need to 'or' into the FT field of SFSR
			// (well, if you want you could take the trap later,
			// all in one place)

	if( trapPrio < 12 ) {
	    dMmuTrap( xact, trapType, faultType, tte, "dmmu: trap " );
	}
    }

	// From this point onward, handle Priority 12 traps only
	//

    bool nonFaulting;

    switch( asi ){
	case Ni_Asi::ASI_PRIMARY_NO_FAULT:
	case Ni_Asi::ASI_SECONDARY_NO_FAULT:
	case Ni_Asi::ASI_PRIMARY_NO_FAULT_LITTLE:
	case Ni_Asi::ASI_SECONDARY_NO_FAULT_LITTLE:
	    nonFaulting = true;
	    break;
	default:
	    nonFaulting = false;
	    break;
    }

    if( (effPriv == 0) && (tte->data4u().getP() == 1) ){
	trapType = Ni_Trap::data_access_exception;
	faultType |= PRIV_VIOLATION;
    }

    if( (tte->data4u().getE() == 1) ){
      if((nonFaulting && (iw->isLoad() || iw->isPrefetch())) ||   // speculative load only, 2/11/04  
	   (opcode == InstructionWord::FLUSH) ){
	    trapType = Ni_Trap::data_access_exception;
 	    if( (faultType & ILLEGAL_INSTR_VA_ASI) == 0 ) {	
	        faultType |= SPEC_LD_FLUSH_TO_EBIT;		
								// v9L1IntTrapData_excp9.s and
 	    }							// v9L1IntTrapData_excp10.s happy
	}							// Jan13, 2004
    }

    if( (tte->data4u().getNFO() == 1) ){
	if( (nonFaulting == false) ){
	    trapType = Ni_Trap::data_access_exception;
	    faultType |= ILLEGAL_FAULT_OP;
	}
    }

// Per explanation by Jim Laudon;
// "The CP bit is only used to determine if a page can be cached in the
// primary caches.  So atomics don't care about the CP bit."
//
//    if( (tte->getDataField( Ni_Tte::CP ) == 0) ){
//	if( iw->isAtomic() == true ){
//	    trapType = Ni_Trap::data_access_exception;
//	    faultType |= ATOMIC_TO_NONCACHEABLE_PAGE;
//	}
//    }


    // PRM V1.2: atomic to IO address causes data_access_exception
    // with FT=0x04    , 2/11/04

    if (iw->isAtomic() && ((paddr >> 39) & 1) ) {
	if( (faultType & ILLEGAL_INSTR_VA_ASI) == 0 ) {
           trapType = Ni_Trap::data_access_exception;
           faultType |= ATOMIC_TO_NONCACHEABLE_PAGE;
	}
    }

    /* If FT=0x02 or 0x04, don't set 0x08    TPS, 2/11/04
    if ((faultType & SPEC_LD_FLUSH_TO_EBIT) ||
	(faultType & ATOMIC_TO_NONCACHEABLE_PAGE)) {
      faultType &= (~ILLEGAL_INSTR_VA_ASI);
    }*/

    if( (iw->isPrefetch() == false) && (trapType != 0) ){
	dMmuTrap( xact, trapType, faultType, tte, "dmmu: trap " );
    }


    if( (iw->isPrefetch() == false) && (tte->data4u().getW() == 0) ){
	if( iw->isStore() || iw->isAtomic() ){
	    trapType  = Ni_Trap::fast_data_access_protection;	// lowest priority among group
								// of priority=12 traps
	    faultType = 0;
	    dMmuTrap( xact, trapType, faultType, tte, "dmmu: write to a read-only page " );
	}
    }
}

////////////////////////////////////////////////////////////////

//static Ni_Tte 	dummyTte = Ni_Tte();

void
Ni_Mmu::handleInstr( MemoryTransaction &t, int &tte_pos )
{
    PaddrT paddr;
    TtePos pos;
    uint_t pgSize = 0;

    uint_t trapType  = 0;
    uint_t faultType = 0;
    Ni_Tte *tte = NULL;
    bool	isRedState = (hpstate_->getRED() ? true : false);
    Uint32T	pid;
    Uint32T	r_bit = 0;
    bool internalXact = t.internalXact();
    AsiT asi = t.asi();
    //Ni_Tte dummyTte;

    pid = mmuState_->getidPartitionIdPtr()->getPID();


    Uint32T	b3, b2, b1, b0, b;
    b3 = sharedState_->getLsuControlRegPtr()->getIM() & 1;
    b2 = hpstate_->getENB() & 1;
    b1 = hpstate_->getHPRIV() & 1;
    b0 = hpstate_->getRED() & 1;
    b = (b3 << 3) | (b2 << 2) | (b1 << 1) | b0;
  
    switch(b) {		// see table 13-16 in section 13.8 in PRM (rev 1.1)

	// ================= IMMU translation: Bypasss  =====================
				// row 1 of table 13-16
				// 4'b???1
				// =======
      case 0x1:			// 4'b0001 	RED bit set, other bits don't care
      case 0x3:			// 4'b0011
      case 0x5:			// 4'b0101
      case 0x7:			// 4'b0111
      case 0x9:			// 4'b1001
      case 0xb:			// 4'b1011
      case 0xd:			// 4'b1101
      case 0xf:			// 4'b1111

				// row 2 of table 13-16
				// 4'b00?0
				// =======
      case 0x0:			// 4'b0000	bit 1=don't care, other bits=0
      case 0x2:			// 4'b0010	bit 1=don't care, other bits=0

				// row 3 of table 13-16
				// 4'b?110
				// =======
      case 0x6:			// 4'b0110	bit 3=don't care
      case 0xe:			// 4'b1110	bit 3=don't care
   	t.vaddr( t.vaddr() & NI_PA_MASK );
	t.paddr( t.vaddr() );
	return; 
	break;

	// ================= IMMU translation: RA->PA  =======================
				// row 4 of table 13-16
      case 0x4:			// 4'b0100
	r_bit = 1;
	break;

	// ================= IMMU translation: VA->PA  =======================
				// row 5 of table 13-16. 
				// 4'b10?0
				// =======
      case 0x8:			// 4'b1000;	
      case 0xa:			// 4'b1010;

				// row 6 of table 13-16
      case 0xc:			// 4'b1100	
				// Nothing special; normal Va->Pa translation
	break;

      default:		// can't get here lest there's some cases missing above
	RIESLING_THROW_DOMAIN_ERROR( "Ni_Mmu::handleInstr(). FIX ME PLEASE" );	
    }

   
    ContextT ctxt = getICtxt( t.asi() );

    if( (t.vaddr() & ~0x03ULL ) != t.vaddr() ){
	iMmuTrap( t, Ni_Trap::mem_address_not_aligned, 0, tte, "immu: unaligned access" );
    }
 
    if( vaddrOutOfRange(t.vaddr()) ) {
        if( pstate_->getAM() == 0 ) {
	    trapType = Ni_Trap::instruction_access_exception;
	    faultType |= VA_OUT_OF_RANGE;
	    iMmuTrap( t, trapType, faultType, tte, "" );
	}
    }

    if (cosimItte_ != 0 && !rtlITlbMiss) {
	// if a itte is provided by testbench, use that instead of looking
	// for a match in itlb.
	// also check that there has not been a immu miss signal from RTL ... 08/25/2005
	Ni_TteDataSun4u *tteData = new Ni_TteDataSun4u();
	tteData->setNative( cosimItte_ );
	// Do not construct here. BIG memory leak. 
	//dummyTte = Ni_Tte(0, 0, *tteData, 0, 0);
        dummyTte.format4u(true);

        dummyTte.setDataField( Ni_Tte::CP,   tteData->getCP() );
	dummyTte.setDataField( Ni_Tte::IE,   tteData->getIE() );
	dummyTte.setDataField( Ni_Tte::CV,   tteData->getCV() );
	dummyTte.setDataField( Ni_Tte::E,    tteData->getE() );
	dummyTte.setDataField( Ni_Tte::P,    tteData->getP() );
	dummyTte.setDataField( Ni_Tte::W,    tteData->getW() );
	dummyTte.setDataField( Ni_Tte::NFO,  tteData->getNFO() );
	dummyTte.setDataField( Ni_Tte::SZL,  tteData->getSZL() );
	dummyTte.setDataField( Ni_Tte::SZH,  tteData->getSZH() );

	tte = &dummyTte;
	paddr = tte->translate(t.vaddr());
	cosimItte_ = 0;
	delete(tteData);
    }
    else {
	pos = itlb_->translate( t.vaddr(), ctxt, pgSize, paddr, pid, r_bit, internalXact, tte_pos );

	if (BlazeCBInterface::cosim()) {
	    if ( pos.nmatches_ != 0 ) {
		if ( rtlITlbMiss ) {		// RTL detects MISS but Riesling doesn't
		    pos.nmatches_ = 0;		// trust RTL and force status to MISS
		}
	    }
	    else {
		if ( rtlITlbMiss==0 ) { 	// Riesling detects MISS but RTL doesn't
					// If RTL has not told us it has caught a TLB miss since
					// the last one, we have probably been hit with that cosim
					// artifact in which the TLB entry was bumped by another 
					// thread. check the victim cache to see if it's there.
					// That's how sas gets arround the problem also.
					// 11/24/03
		    pos = itlb_->translateUsingVictimTlb( t.vaddr(), ctxt, pgSize, paddr, pid, r_bit );
		}
	    }
	    if ( rtlITlbMiss ) {		// RTL detects MISS but Riesling doesn't
	        // Zero cosimItte_ in case rtlITlbmiss has been set ... 08/25/2005
	        cosimItte_ = 0;
	    }
	}

	if(pos.nmatches_ == 0 ) {
	    
	    if( ! internalXact ) {
		rtlITlbMiss = 0;
	    }
	    
	    if( r_bit == 0 )
	    {
		iMmuTrap( t, Ni_Trap::fast_instruction_access_MMU_miss, 0, tte, "immu: mmu miss" );
	    }
	    else
	    {
		iMmuTrap( t, Ni_Trap::inst_real_translation_miss, 0, tte, "immu: real mmu miss" );
	    }
	    
	}

	tte = (Ni_Tte*)pos.tte_;
    }

    if( pstate_->getPRIV() == 0 &&  tte->data4u().getP() == 1){

	mmuState_->getiTlbTagAccessPtr()->setCONTEXT( ctxt );
	mmuState_->getiTlbTagAccessPtr()->setVA_63_13( t.vaddr() >> 13 );

	iMmuTrap( t, Ni_Trap::instruction_access_exception, 
		PRIV_VIOLATION, tte, "immu: access to priv page in nonpriv mode" );

    }
    
    // paddr = getNewPaddr( paddr, tte->data4u().getCP() );
    // t.paddr( paddr );
    t.paddr ( paddr & NI_PA_MASK );
    //delete(tte);
}



////////////////////////////////////////////////////////////////

bool
Ni_Mmu::translate( MemoryTransaction &xact )
{
    int tte_pos = 0;
    if( !xact.readXact() && !xact.writeXact() ){
	RIESLING_THROW_INVALID_ARGUMENT( string("Access type ").append( StringUtils::uint642HexString( xact.access() )).
		    append( " is neither a READ nor a WRITE request." ) );
    }

    if( xact.referenceType() == MemoryTransaction::DATA ){
	handleData( xact );
    } else if( xact.referenceType() == MemoryTransaction::INSTR ){
	handleInstr( xact, tte_pos );
    } else {
	RIESLING_THROW_INVALID_ARGUMENT( string("Reference type ").append( StringUtils::uint642HexString( xact.access() )).
		    append( " is neither a DATA nor a INSTR reference." ) );
    }

    return true;
}

////////////////////////////////////////////////////////////////

bool
Ni_Mmu::checkInstrVaWatchpoint( const MemoryTransaction &t )
{
    return false;		// Ni does not have Inst Watchpoint
}

////////////////////////////////////////////////////////////////

bool
Ni_Mmu::checkInstrPaWatchpoint( const MemoryTransaction &t )
{
    return false;		// Ni does not have Inst Watchpoint
}


/**
 * If the mask is cleared, then watchpoints are disabled
 * Internal requests are not subject to watchpoint check
 */
bool 
Ni_Mmu::checkDataWatchpoint( const MemoryTransaction &t,
			 uint8_t mask, 
			 bool read, 
			 bool write,
			 Uint64T currentAddr,
			 Uint64T watchpointAddr )
{
  InstructionWord iw;

  if( !t.getInstruction( iw ) ){
    RIESLING_THROW_DOMAIN_ERROR( "No valid instruction word for this memory transaction" );
  }

  if(pstate_->getAM()){
      watchpointAddr &= 0x0ffffffffULL;
  }
  if (mask && !t.internalXact() && 
	(((write || read) && t.atomic()) ||
	 // rdwrXact() means an internal read followed by a real write, 
	 // e.g., stdfa on ASI_PST8_PRIMARY..ASI_PST32_SECONDARY_LITTLE, 
	 // the watchpoint trap should occur on the write side, but other
	 // traps checking occurres on the read side, so make it consistent,
	 // but the checking must be conducted as if it is a write.
	 (write && t.rdwrXact()) ||
	 (!t.rdwrXact() && ((t.writeXact() && write) || (t.readXact() && read))))) {
	 if ((currentAddr & ~7ull) == watchpointAddr) {
	    switch (t.size())
	    {
	    case 64:
	    case 16:
	    case 8: assert((currentAddr & 7ull) == 0); return mask != 0;
	    case 4: assert((currentAddr & 3ull) == 0); return ((mask >> (currentAddr & 4ull)) & 0xf) != 0;
	    case 2: assert((currentAddr & 1ull) == 0); return ((mask >> (currentAddr & 6ull)) & 0x3) != 0;
	    case 1:                                    return ((mask >> (currentAddr & 7ull)) & 0x1) != 0;
	    default: assert(0);
	    }
	}
    }
    return false;

  /*if (mask && (t.writeXact() && write || t.readXact() && read) && !t.internalXact()) { 
    Uint64T addr_offset = currentAddr & 0x7ull;       // start byte in an 8-byte word
    Uint64T size_mask;                                // word access will have the least 4 bits set
    size_mask = (~(0xffffffffffffffff << t.size()))   // max size could be 64 bytes, ie, 64 bits
      & 0xffull;                                      // only care the least 8 bytes, ie, 8 bits
    Uint64T addr_mask = 0xfffffffffffffff8;

    return (((currentAddr & addr_mask) == watchpointAddr) && ((mask >> addr_offset) & size_mask));
  }
  else
    return false;*/
  
}

////////////////////////////////////////////////////////////////

bool
Ni_Mmu::checkDataPaWatchpoint( const MemoryTransaction &t )
{
    return false;	
}

////////////////////////////////////////////////////////////////
	
bool
Ni_Mmu::checkDataVaWatchpoint( const MemoryTransaction &t )
{
    return
    checkDataWatchpoint( t,
			 sharedState_->getLsuControlRegPtr()->getVM(),
		         sharedState_->getLsuControlRegPtr()->getVR(),
			 sharedState_->getLsuControlRegPtr()->getVW(),
			 Ni_ArchState::vaddrSignExtend(t.vaddr()),
			 Ni_ArchState::vaddrSignExtend(mmuState_->getVirtualWatchpointPtr()->getNative() & ~0x7ULL) );

}

////////////////////////////////////////////////////////////////



void 
Ni_Mmu::commitWrite( AsiDispatchPacket &p, MmuTypeT idSel )
{
    Uint64T data = p.getData();
    Uint32T	pid;
    Uint32T	r_bit = ( (p.getVaddr()>>9) & 1 ) ;	// r-bit is set is bit 9 of Va is set
    Uint32T	isSun4v = ( (p.getVaddr()>>10) & 1 ) ;	// bit10 == 0 => Sun4u, bit10==1 => Sun4v

    Uint64T	iTagAccessVa, dTagAccessVa;
    ContextT	iTagAccessCtxt, dTagAccessCtxt;

    iTagAccessCtxt = mmuState_->getiTlbTagAccessPtr()->getCONTEXT();	// MMU-30
    dTagAccessCtxt = mmuState_->getdTlbTagAccessPtr()->getCONTEXT();	// MMU-30

    iTagAccessVa = mmuState_->getiTlbTagAccessPtr()->getVA_63_13() << 13;	// MMU-30
    dTagAccessVa = mmuState_->getdTlbTagAccessPtr()->getVA_63_13() << 13;	// MMU-30

    pid = mmuState_->getidPartitionIdPtr()->getPID();

    switch( p.getAccessIndex() ){

	case PRIMARY_CONTEXT:
	    if( idSel == INSTRUCTION || idSel == DATA ){
		mmuState_->setPrimaryDContext( data );	// MMU-24. I and D share one Primary Context Reg
	    } else {
		RIESLING_THROW_INVALID_ARGUMENT( "idSel is neither INSTRUCTION nor DATA" );
	    }
	    break;

	case SECONDARY_CONTEXT:
		mmuState_->setSecondaryContext(data);
		break;

	case I_SYNC_FAULT_STATUS:
	        mmuState_->getiSfsrPtr()->setNative(data);
	        break;

	case D_SYNC_FAULT_STATUS:
	        mmuState_->getdSfsrPtr()->setNative(data);
	        break;

	case D_CTXT_ZERO_TSB_BASE_PS0:
		mmuState_->getdCtxtZeroTsbBasePs0Ptr()->setNative(data);
		if(p.getInternal())
			break;
		if(dTagAccessCtxt == 0 ) {		// MMU-4
	            mmuState_->setdTsbPs0Pointer( genTsbPointer( dTagAccessVa, TSB_PS0_POINTER, dTagAccessCtxt, DATA) ); 
	        }

		break;

	case D_CTXT_ZERO_TSB_BASE_PS1:
		mmuState_->getdCtxtZeroTsbBasePs1Ptr()->setNative(data);
		if(p.getInternal())		
			break;
		if(dTagAccessCtxt == 0 ) {		// MMU-4
	            mmuState_->setdTsbPs1Pointer( genTsbPointer( dTagAccessVa, TSB_PS1_POINTER, dTagAccessCtxt, DATA) ); 
		}
		break;

	case D_CTXT_ZERO_CONFIG:
		mmuState_->getdCtxtZeroConfigPtr()->setNative(data);
		break;
		
	case I_CTXT_ZERO_TSB_BASE_PS0:
		mmuState_->getiCtxtZeroTsbBasePs0Ptr()->setNative(data);
		if(p.getInternal())
			break;
		if(iTagAccessCtxt == 0 ) {		// MMU-4
	            mmuState_->setiTsbPs0Pointer( genTsbPointer( iTagAccessVa, TSB_PS0_POINTER, iTagAccessCtxt, INSTRUCTION) ); 
		}
		break;

	case I_CTXT_ZERO_TSB_BASE_PS1:
		mmuState_->getiCtxtZeroTsbBasePs1Ptr()->setNative(data);
		if(p.getInternal())
			break;
		if(iTagAccessCtxt == 0 ) {		// MMU-4
	            mmuState_->setiTsbPs1Pointer( genTsbPointer( iTagAccessVa, TSB_PS1_POINTER, iTagAccessCtxt, INSTRUCTION) ); 
		}
		break;

	case I_CTXT_ZERO_CONFIG:
		mmuState_->getiCtxtZeroConfigPtr()->setNative(data);
		break;		
		
	case D_CTXT_NONZERO_TSB_BASE_PS0:
		mmuState_->getdCtxtNonzeroTsbBasePs0Ptr()->setNative(data);
		if(p.getInternal())
			break;
		if(dTagAccessCtxt != 0 ) {		// MMU-4
	            mmuState_->setdTsbPs0Pointer( genTsbPointer( dTagAccessVa, TSB_PS0_POINTER, dTagAccessCtxt, DATA) ); 
		}
		break;

	case D_CTXT_NONZERO_TSB_BASE_PS1:
		mmuState_->getdCtxtNonzeroTsbBasePs1Ptr()->setNative(data);
		if(p.getInternal())
			break;
		if(dTagAccessCtxt != 0 ) {		// MMU-4
	            mmuState_->setdTsbPs1Pointer( genTsbPointer( dTagAccessVa, TSB_PS1_POINTER, dTagAccessCtxt, DATA) ); 
		}
		break;

	case D_CTXT_NONZERO_CONFIG:
		mmuState_->getdCtxtNonzeroConfigPtr()->setNative(data);
		break;
		
	case I_CTXT_NONZERO_TSB_BASE_PS0:
		mmuState_->getiCtxtNonzeroTsbBasePs0Ptr()->setNative(data);
		if(p.getInternal())
			break;
		if(iTagAccessCtxt != 0 ) {		// MMU-4
	            mmuState_->setiTsbPs0Pointer( genTsbPointer( iTagAccessVa, TSB_PS0_POINTER, iTagAccessCtxt, INSTRUCTION) ); 
		}
		break;

	case I_CTXT_NONZERO_TSB_BASE_PS1:
		mmuState_->getiCtxtNonzeroTsbBasePs1Ptr()->setNative(data);
		if(p.getInternal())
			break;
		if(iTagAccessCtxt != 0 ) {		// MMU-4
	            mmuState_->setiTsbPs1Pointer( genTsbPointer( iTagAccessVa, TSB_PS1_POINTER, iTagAccessCtxt, INSTRUCTION) ); 
		}
		break;

	case I_CTXT_NONZERO_CONFIG:
		mmuState_->getiCtxtNonzeroConfigPtr()->setNative(data);
		break;

	case I_TLB_TAG_ACCESS:
	    {
    	    ContextT  ctxt;
	    Uint64T vaddr;

	    data = data & NI_VA_MASK;
	    // N1 RTL does not mask out the upper 32-bit when it is software
	    // doing the read/write
// 	    if(pstate_->getAM()){
// 		data &= 0x0ffffffffULL;
// 	    }
	    mmuState_->getiTlbTagAccessPtr()->setNative( data );
	    if(p.getInternal())		
		break;
	    mmuState_->getiTsbTagTargetPtr()->setVA_63_22( data >> 22 );
	    mmuState_->getiTsbTagTargetPtr()->setCONTEXT( mmuState_->getiTlbTagAccessPtr()->getCONTEXT() );

	    // update TSB pointer regs		// MMU-4
	    ctxt = mmuState_->getiTlbTagAccessPtr()->getCONTEXT();
	    vaddr = data & ~(0x1fff);
	    mmuState_->setiTsbPs0Pointer( genTsbPointer( vaddr, TSB_PS0_POINTER, ctxt, INSTRUCTION) ); 
	    mmuState_->setiTsbPs1Pointer( genTsbPointer( vaddr, TSB_PS1_POINTER, ctxt, INSTRUCTION) );  

	    }
		break;

	case I_TSB_PS0_POINTER:
		mmuState_->setiTsbPs0Pointer(data);
		break;

	case I_TSB_PS1_POINTER:
		mmuState_->setiTsbPs1Pointer(data);
		break;

	case I_TLB_DATA_IN:
	    {
		mmuState_->setiDataIn( data );
		if(p.getInternal())
		    break;
	        doTlbDataInWrite(INSTRUCTION, p);
		//mmuState_->setiDataIn( data );
	    }
	    break;

	case I_TLB_DATA_ACCESS:
	    {
		mmuState_->setiDataAccess( data );
		if(p.getInternal())
		    break;
	        doTlbDataAccessWrite(INSTRUCTION, p);
		//mmuState_->setiDataAccess( data );
	    }
	    break;

	case I_TLB_DEMAP:
	    {
		if(p.getInternal())
		    break;
		VaddrT vaddr = p.getVaddr();
		demap( p, INSTRUCTION);
	    }
	    break;

	case D_TLB_TAG_ACCESS:
	    {
    	    ContextT  ctxt;
	    Uint64T vaddr;

	    data = data & NI_VA_MASK;
	    // N1 RTL does not mask out the upper 32-bit when it is software
	    // doing the read/write
// 	    if(pstate_->getAM()){
// 		data &= 0x0ffffffffULL;
// 	    }
	    mmuState_->getdTlbTagAccessPtr()->setNative( data );
	    if(p.getInternal())
		break;
	    mmuState_->getdTsbTagTargetPtr()->setVA_63_22( data >> 22 );
	    mmuState_->getdTsbTagTargetPtr()->setCONTEXT( mmuState_->getdTlbTagAccessPtr()->getCONTEXT() );
	
	    	// update TSB pointer regs		// MMU-4
	    ctxt = mmuState_->getdTlbTagAccessPtr()->getCONTEXT();
	    vaddr = data & ~(0x1fff);
	    mmuState_->setdTsbPs0Pointer( genTsbPointer( vaddr, TSB_PS0_POINTER, ctxt, DATA) ); 
	    mmuState_->setdTsbPs1Pointer( genTsbPointer( vaddr, TSB_PS1_POINTER, ctxt, DATA) );  

	    }

	    break;

	case VIRTUAL_WATCHPOINT:
		mmuState_->getVirtualWatchpointPtr()->setNative(data);
		break;

	case ID_PARTITION_ID:
		mmuState_->getidPartitionIdPtr()->setNative(data);
		break;

	case D_TSB_PS0_POINTER:
		mmuState_->setdTsbPs0Pointer(data);
		break;

	case D_TSB_PS1_POINTER:
		mmuState_->setdTsbPs1Pointer(data);
		break;

	case D_TSB_DIRECT_POINTER:
		mmuState_->setdTsbDirectPointer(data);
		break;

	case D_TLB_DATA_IN:
	    {
		if(p.getInternal())
		    break;
		mmuState_->setdDataIn( data );
	        doTlbDataInWrite(DATA, p);
		//mmuState_->setdDataIn( data );
	    }
	    break;

	case D_TLB_DATA_ACCESS:
	    {
		if(p.getInternal())
		    break;	
		mmuState_->setdDataAccess( data );
	        doTlbDataAccessWrite(DATA, p);
		//mmuState_->setdDataAccess( data );
	    }
	    break;

	case D_TLB_DEMAP:
	    {
		if(p.getInternal())
		    break;
		VaddrT vaddr = p.getVaddr();

		demap( p, DATA);
	    }
	    break;

	case I_TLB_INVALIDATE_ALL:
	    if(p.getInternal())
		break;
	    itlb_->invalidateAll();
	    break;

	case D_TLB_INVALIDATE_ALL:
	    if(p.getInternal())
		break;
	    dtlb_->invalidateAll();
	    break;

	case MMU_UNIMPLEMENTED:
	    break;

	default:
	    break;
    }

}

////////////////////////////////////////////////////////////////

void 
Ni_Mmu::asiReadHandler( AsiDispatchPacket &p )
{
    Uint64T data = 0;

    p.setResponse( AsiDispatchPacket::OK );

    switch( p.getAccessIndex() ){

	case LSU_CONTROL:
    	    data = sharedState_->getLsuControlRegPtr()->getNative();
	    break;

	case PRIMARY_CONTEXT:
		data = mmuState_->getPrimaryDContext();
		break;

	case SECONDARY_CONTEXT:
		data = mmuState_->getSecondaryContext();
		break;

	case I_SYNC_FAULT_STATUS:
	        data = mmuState_->getiSfsrPtr()->getNative( );
	        break;

	case D_SYNC_FAULT_STATUS:
	        data = mmuState_->getdSfsrPtr()->getNative( );
	        break;

	case SYNC_FAULT_ADDRESS:
	        data = mmuState_->getSyncFaultAddress();
	        break;

	case I_TSB_TAG_TARGET:
		data = mmuState_->getiTsbTagTargetPtr()->getNative();
		break;

	case D_CTXT_ZERO_TSB_BASE_PS0:
		data = mmuState_->getdCtxtZeroTsbBasePs0Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    

		break;

	case D_CTXT_ZERO_TSB_BASE_PS1:
		data = mmuState_->getdCtxtZeroTsbBasePs1Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    
		break;

	case D_CTXT_ZERO_CONFIG:
		data = mmuState_->getdCtxtZeroConfigPtr()->getNative();
		break;
		
	case I_CTXT_ZERO_TSB_BASE_PS0:
		data = mmuState_->getiCtxtZeroTsbBasePs0Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    
		break;

	case I_CTXT_ZERO_TSB_BASE_PS1:
		data = mmuState_->getiCtxtZeroTsbBasePs1Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    
		break;

	case I_CTXT_ZERO_CONFIG:
		data = mmuState_->getiCtxtZeroConfigPtr()->getNative();
		break;
		
	case D_TSB_TAG_TARGET:
		data = mmuState_->getdTsbTagTargetPtr()->getNative();
		break;
		
	case D_CTXT_NONZERO_TSB_BASE_PS0:
		data = mmuState_->getdCtxtNonzeroTsbBasePs0Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    
		break;

	case D_CTXT_NONZERO_TSB_BASE_PS1:
		data = mmuState_->getdCtxtNonzeroTsbBasePs1Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    
		break;

	case D_CTXT_NONZERO_CONFIG:
		data = mmuState_->getdCtxtNonzeroConfigPtr()->getNative();
		break;

		
	case I_CTXT_NONZERO_TSB_BASE_PS0:
		data = mmuState_->getiCtxtNonzeroTsbBasePs0Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    
		break;

	case I_CTXT_NONZERO_TSB_BASE_PS1:
		data = mmuState_->getiCtxtNonzeroTsbBasePs1Ptr()->getNative();
	        if( data &  NI_VA_BIT47 ){		// MMU-3
		    data |= (~NI_VA_MASK);
	        } else {
		    data &= (NI_VA_MASK);
	        }    
		break;

	case I_CTXT_NONZERO_CONFIG:
		data = mmuState_->getiCtxtNonzeroConfigPtr()->getNative();
		break;

	case I_TLB_TAG_ACCESS:
	    data = mmuState_->getiTlbTagAccessPtr()->getNative( );
	    break;

	case I_TSB_PS0_POINTER:
		data = mmuState_->getiTsbPs0Pointer();
		break;

	case I_TSB_PS1_POINTER:
		data = mmuState_->getiTsbPs1Pointer();
		break;

	case I_TLB_DATA_ACCESS:
    	{
	    // initiate an internal read of the DATA portion of the specified TLB entry
	    const Ni_Tte *niTte = dynamic_cast<const Ni_Tte *>( itlb_->get( getTteIdx( p.getVaddr() ) ).tte_ );


	    data = encodeTteDataReg(niTte);
	}

	    break;

	case I_TLB_TAG_READ:
	{
	    // initiate an internal read of the TAG portion of the specified TLB entry 
	    const Ni_Tte *niTte = dynamic_cast<const Ni_Tte *>( itlb_->get( getTteIdx( p.getVaddr() ) ).tte_ );	

	    data = encodeTteTagReg(niTte);
	}

	    break;

	case D_TLB_TAG_ACCESS:
	    data = mmuState_->getdTlbTagAccessPtr()->getNative( );
	    break;

	case VIRTUAL_WATCHPOINT:
		data = mmuState_->getVirtualWatchpointPtr()->getNative();
		break;

	case ID_PARTITION_ID:
		data = mmuState_->getidPartitionIdPtr()->getNative();
		break;

	case D_TSB_PS0_POINTER:
		data = mmuState_->getdTsbPs0Pointer();
		break;

	case D_TSB_PS1_POINTER:
		data = mmuState_->getdTsbPs1Pointer();
		break;

	case D_TSB_DIRECT_POINTER:
		data = mmuState_->getdTsbDirectPointer();
		break;

	case D_TLB_DATA_ACCESS:
	{
	    // initiate an internal read of the DATA portion of the specified TLB entry
	    const Ni_Tte *niTte = dynamic_cast<const Ni_Tte *>( dtlb_->get( getTteIdx( p.getVaddr() ) ).tte_ );

	    data = encodeTteDataReg(niTte);

	}
	    break;

	case D_TLB_TAG_READ:
	{
	    // initiate an internal read of the TAG portion of the specified TLB entry 
	    const Ni_Tte *niTte = dynamic_cast<const Ni_Tte *>( dtlb_->get( getTteIdx( p.getVaddr() ) ).tte_ );

	    data = encodeTteTagReg(niTte);
	}
	    break;

	case MMU_UNIMPLEMENTED:
	    data = 0;
	    break;

	default:
	    p.setResponse( AsiDispatchPacket::HANDLER_ERROR );
	    break;
    }

    p.setData( data );


}

////////////////////////////////////////////////////////////////

void 
Ni_Mmu::asiWriteHandler( AsiDispatchPacket &p )
{
    Uint64T	data;

    data = p.getData();
	
    p.setResponse( AsiDispatchPacket::OK );

    switch( p.getAccessIndex() ){

	case LSU_CONTROL:
	  // The Ni uses Sf_LsuControlReg as LsuControlReg. However, the FM, PW,
          // PR, and PM fields in Ni are reserved, i.e., RO.
	    data = data & 0x1fe60000full; 
    	    sharedState_->getLsuControlRegPtr()->setNative(data);                      
	    break;

	case ID_PARTITION_ID:
	case PRIMARY_CONTEXT:
	    d_commitQueue_.push_back( p );
	    i_commitQueue_.push_back( p );
	    break;

	case I_SYNC_FAULT_STATUS:
	case I_CTXT_ZERO_TSB_BASE_PS0:
	case I_CTXT_ZERO_TSB_BASE_PS1:
	case I_CTXT_ZERO_CONFIG:
	case I_CTXT_NONZERO_TSB_BASE_PS0:
	case I_CTXT_NONZERO_TSB_BASE_PS1:
	case I_CTXT_NONZERO_CONFIG:
	case I_TLB_TAG_ACCESS:
	case I_TSB_PS0_POINTER:
	case I_TSB_PS1_POINTER:
	case I_TLB_DATA_IN:
	case I_TLB_DATA_ACCESS:
	case I_TLB_DEMAP:
	case I_TLB_INVALIDATE_ALL:
	    i_commitQueue_.push_back( p );
	    break;

	case D_SYNC_FAULT_STATUS:
	case SECONDARY_CONTEXT:
	case D_CTXT_ZERO_TSB_BASE_PS0:
	case D_CTXT_ZERO_TSB_BASE_PS1:
	case D_CTXT_ZERO_CONFIG:
	case D_CTXT_NONZERO_TSB_BASE_PS0:
	case D_CTXT_NONZERO_TSB_BASE_PS1:
	case D_CTXT_NONZERO_CONFIG:
	case D_TLB_TAG_ACCESS:
	case VIRTUAL_WATCHPOINT:
	case D_TSB_PS0_POINTER:
	case D_TSB_PS1_POINTER:
	case D_TSB_DIRECT_POINTER:
	case D_TLB_DATA_IN:
	case D_TLB_DATA_ACCESS:
	case D_TLB_DEMAP:
	case D_TLB_INVALIDATE_ALL:

	case MMU_UNIMPLEMENTED:
	    d_commitQueue_.push_back( p );
	    break;

	default:
	    p.setResponse( AsiDispatchPacket::HANDLER_ERROR );
	    break;
    }

	// src/bcore/cpu_exec2.cc expects a Sf style MMU of which the
        // AsiWrites to MMU are only committed after FLUSH, DONE or RETRY.
	// For Ni MMU this is not true . So we always
	// always commit all ASI Writes immediately. 
	// Note that when cpu_exec2.cc calls commitAllAsiWrites, 
	// commitDataAsiWrites or commitInstrAsiWrite, these functions
	// will do nothing because the queues are always empty


    commitAllAsiWrites();


}
////////////////////////////////////////////////////////////////

void
Ni_Mmu::commitDataAsiWrites()
{

    commit( d_commitQueue_, DATA );

}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::commitInstrAsiWrites()
{

    commit( i_commitQueue_, INSTRUCTION );

}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::commitAllAsiWrites()
{

    commit( d_commitQueue_, DATA );
    commit( i_commitQueue_, INSTRUCTION );

}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::commit( list<AsiDispatchPacket> &commitQueue, MmuTypeT idSel )
{
			// 8/14/03
			// if the commitWrite() traps, the faulting AsiDispatchPacket p
			// is removed from the queue and won't be re-committed the next time
			//
    while( ! commitQueue.empty() ){
        AsiDispatchPacket p = commitQueue.front();
	commitQueue.pop_front();
	commitWrite( p, idSel );	    
    }

}

////////////////////////////////////////////////////////////////
void
Ni_Mmu::demap( AsiDispatchPacket &p, MmuTypeT idSel )
{
    Ni_Tlb	*tlb ;
    Uint64T     data = p.getData();
    Uint32T	pid;
    Uint32T	r_bit = ( (p.getVaddr()>>9) & 1 ) ;	// r-bit is set is bit 9 of Va is set

    ContextT    ctxt;
    Uint64T	type;
    Uint64T 	contextId;
    VaddrT	vaddr;
    AsiT	asi;

    asi = p.getAsi();

    vaddr = p.getVaddr();

    contextId = (vaddr >> 4) & 0x3;
    type = (vaddr >> 6) & 0x3;

    vaddr = vaddr & ~0x1fffULL;

    pid = mmuState_->getidPartitionIdPtr()->getPID();

    if( idSel == DATA ) {
	tlb = dtlb_;
    } else {
	tlb = itlb_;
    }


    switch( contextId ){
	case 0:
	    if( idSel == INSTRUCTION || idSel == DATA ){
		ctxt = mmuState_->getPrimaryDContext();		// I and D share one Primary Context register
	    } else {
		RIESLING_THROW_INVALID_ARGUMENT( "idSel is not INSTR or DATA" );
	    }
	    break;

	case 1:
	    if( idSel == INSTRUCTION )
		return;		// itlb 2ndary context demap not supported and ignored. see Ni PRM
	    else
	        ctxt = mmuState_->getSecondaryContext();
	    break;

	case 2:
	    ctxt = 0;
	    break;

	case 3:
	    if( type != 2 ) {	// MMU-27. Reserved contextID=3 for demapAll is OK.
		return;	   	// this is reserved. demap request is ignored.
	    }
	    break;
	default:
	    RIESLING_THROW_OUT_OF_RANGE( "contextId out of range" );
	    break;
    }

    switch( type ){
	case 0:
// TODO. Jan20,2004
// PRM section 13.12.1 says VA must be in range but
// Niagara MMU does not do VA hole check in demap. PRM version 1.1 is wrong.
// MMU-26 is therefore invalid and not needed. PRM will be corrected in 1.2
//
//
	    if( vaddr &  NI_VA_BIT47 ){
		vaddr |= (~NI_VA_MASK);
	    } else {
		vaddr &= (NI_VA_MASK);
	    }    

	    tlb->demapByPage( vaddr, ctxt, 0, pid, r_bit );
	    break;
	case 1:
	    tlb->demapByContext( ctxt, pid );
	    break;
	case 2:
	    tlb->demapAll( pid );
	    break;
	default:
	    //RIESLING_THROW_OUT_OF_RANGE( "type out of range" );
	    break;
    }



}


////////////////////////////////////////////////////////////////

void
Ni_Mmu::updateTagRegisters( Sf_TagTargetReg *tTarget, 
			    Sf_TagAccessReg *tAccess, 
			    ContextT        ctxt,
			    VaddrT          vaddr )
{



    if( vaddr &  NI_VA_BIT47 ){
	vaddr |= (~NI_VA_MASK);
    } else {
	vaddr &= (NI_VA_MASK);
    }
    if(pstate_->getAM()){
	vaddr &= 0x0ffffffffULL;
    }

    tTarget->setCONTEXT( ctxt );
    tTarget->setVA_63_22( vaddr >> 22 );
    tAccess->setCONTEXT( ctxt );
    tAccess->setVA_63_13( vaddr >> 13 );


}

////////////////////////////////////////////////////////////////
	
TlbIndexT
Ni_Mmu::getTteIdx( Uint64T data ) const
{
    return ( data >> 3 ) & 0x3f;
}

////////////////////////////////////////////////////////////////

void 
Ni_Mmu::setAsiDispatcher( AsiDispatcher & )
{

}

void
Ni_Mmu::setSharedState( Sf_SharedState *sharedState,  Ni_HpstateReg *hpstate, V9_PstateReg *pstate )
{
    sharedState_ = sharedState;
    hpstate_ = hpstate;
    pstate_ = pstate;
}

void
Ni_Mmu::setTlb( Ni_Tlb *itlb, Ni_Tlb *dtlb )
{
    itlb_ = itlb;
    dtlb_ = dtlb;
}

////////////////////////////////////////////////////////////////

Ni_MmuState *
Ni_Mmu::getMmuStatePtr()
{
    return mmuState_;
}

////////////////////////////////////////////////////////////////

Ni_MmuState *
Ni_Mmu::getNewMmuState()
{
    return new Ni_MmuState;
}

////////////////////////////////////////////////////////////////

AsiObject *
Ni_Mmu::getAsiObject() const
{
    return Ni_Asi::getInstance();
}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::iMmuTrap( MemoryTransaction &req, 
	          uint_t trapType, 
		  uint_t faultType, 
		  Tte* tte_,
		  const string &descr )
{
    Ni_Tte* tte = (Ni_Tte*)tte_;
    bool updateSfsr = false;

    AsiT asi = req.asi();
    AsiObject *asiObj = getAsiObject();

    Uint64T vaddr = req.vaddr();


    if( req.internalXact() ) {
		// for internal transactions (one that is not generated by executing an
		// instruction but from riesling itself), don't update mmu registers
	throw BasicTrap( trapType, descr );
    }

    if( vaddr & NI_VA_BIT47 ){
	vaddr |= ~NI_VA_MASK;
    } else {
	vaddr &= NI_VA_MASK;
    }
    if(pstate_->getAM()){
        vaddr &= 0x0ffffffffULL;
    }


    if( trapType == Ni_Trap::instruction_access_exception ){
	updateSfsr = true;
    } else {
	updateSfsr = false;
    }


    if( updateSfsr ){
	updateSfsReg(INSTRUCTION, asi, faultType, 0, 0);
    }

//     if (!((trapType == Ni_Trap::instruction_access_exception) &&
// 	  ((faultType == Ni_Mmu::VA_OUT_OF_RANGE_JMPL_RETURN) ||
// 	   (faultType == Ni_Mmu::VA_OUT_OF_RANGE)))) {
// 	// Contents of i_tag_access undefined if instruction_access_exception 
// 	// is due to virtual address out of range.

    if (1) {
	// although instruction_access_exception with va-out-of-range will
	// result in itag_access, etc. to be undefined, it appears that
	// rtl/simics decide to update the registers anyways to keep testbench
	// register compareison happy.
	if (faultType == Ni_Mmu::VA_OUT_OF_RANGE_JMPL_RETURN) {
	    // VA_OUT_OF_RANGE_JMPL_RETURN passes in targetPC, but testbench
	    // seems to expect instruction PC for comparison.
	    MemoryTransaction* ptr0 = (MemoryTransaction*)&req;
	    vaddr = ((Ni_Strand*)ptr0->getStrand())->getArchStatePtr()->getPc();
	}

	ContextT  ctxt;

	if ( tte == NULL ) {
	    if ( asiObj->isPrimaryCtxt( asi ) ) {
		ctxt = mmuState_->getPrimaryDContext();
	    } 
	    else if ( asiObj->isSecondaryCtxt( asi ) ) {
		ctxt = mmuState_->getSecondaryContext();
	    } 
	    else if ( asiObj->isNucleusCtxt( asi ) ) {
		ctxt = 0;
	    } 
	    else {
		if ( trapType == Ni_Trap::instruction_access_exception ) {
		    ctxt = 0; // undefined value
		}
	    } 
	} 
	else {
	    ctxt = tte->context();
	}

	updateTagRegisters( mmuState_->getiTsbTagTargetPtr(),
			    mmuState_->getiTlbTagAccessPtr(),
			    ctxt,
			    vaddr );
	mmuState_->setiTsbPs0Pointer( genTsbPointer( vaddr, TSB_PS0_POINTER, ctxt, INSTRUCTION ) ); 
	mmuState_->setiTsbPs1Pointer( genTsbPointer( vaddr, TSB_PS1_POINTER, ctxt, INSTRUCTION) );  
    }

    throw BasicTrap( trapType, descr );
}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::dMmuTrap( MemoryTransaction &req, 
		  uint_t trapType, 
		  uint_t faultType, 
		  Tte* tte_,
		  const string &descr )
{
    Ni_Tte* tte = (Ni_Tte*)tte_;
    bool updateSfsr = false;

    AsiT asi = req.asi();
    AsiObject *asiObj = getAsiObject();

    if( req.internalXact() ) {
		// for internal transactions (one that is not generated by executing an
		// instruction but from riesling itself), don't update mmu registers
	throw BasicTrap( trapType, descr );
    }

    InstructionWord iw;

    if( req.getInstruction( iw ) == false ){
	RIESLING_THROW_DOMAIN_ERROR( "D-MMU: No valid instruction word for this memory transaction" );
    }

    Uint64T vaddr = req.vaddr();

    if( vaddr & NI_VA_BIT47 ){
	vaddr |= ~NI_VA_MASK;
    } else {
	vaddr &= NI_VA_MASK;
    }
    if(pstate_->getAM()){
        vaddr &= 0x0ffffffffULL;
    }


    switch( trapType ){
	case Ni_Trap::data_access_exception:
	    updateSfsr = true;
	    break;

	case Ni_Trap::fast_data_access_protection:
	case Ni_Trap::privileged_action:
	case Ni_Trap::VA_watchpoint:
	case Ni_Trap::PA_watchpoint:
	case Ni_Trap::mem_address_not_aligned:
	case Ni_Trap::LDDF_mem_address_not_aligned:
	case Ni_Trap::STDF_mem_address_not_aligned:
	case Ni_Trap::LDQF_mem_address_not_aligned:
	case Ni_Trap::STQF_mem_address_not_aligned:
	    faultType = 0;
	    updateSfsr = true;

	break;

	default:
	    updateSfsr = false;
	    break;
    }

    /* asi for JMPL and RETURN instructions does not depend on tl for mem_address_not_aligned traps*/
    if(trapType == Ni_Trap::mem_address_not_aligned && (iw.op() == 2 && (iw.op3() & ~1) == 0x38)){
	asi = pstate_->getCLE() ? V9_Asi::ASI_PRIMARY_LITTLE : V9_Asi::ASI_PRIMARY;
    }

    if( updateSfsr ){


	uint8_t isWr = iw.isStore() || iw.isAtomic();
 	uint8_t ebit;

        if ( tte == NULL ) {
	    ebit = 0;
	} else {
	    ebit = tte->getDataField( Ni_Tte::E );
	}

	updateSfsReg(DATA, asi, faultType, isWr, ebit);

	mmuState_->setSyncFaultAddress(vaddr);

    }

    // either stores the value of primary context 0 or secondary context 0 
    // or zeroes.  The tag_access registers do not have direct access to the 
    // TLBs (or the TTEs).
    ContextT ctxt = 0;
    if (asiObj->isPrimaryCtxt(asi)) {
	ctxt = mmuState_->getPrimaryDContext();
    }
    else if (asiObj->isSecondaryCtxt(asi)) {
	ctxt = mmuState_->getSecondaryContext();
    }
    else if (asiObj->isNucleusCtxt(asi)) {
	ctxt = 0;
    }

//     if( tte == NULL ){
// 	if( asiObj->isPrimaryCtxt( asi )){
// 	    ctxt = mmuState_->getPrimaryDContext();
// 	} else if( asiObj->isSecondaryCtxt( asi ) ){
// 	    ctxt = mmuState_->getSecondaryContext();
// 	} else if( asiObj->isNucleusCtxt( asi ) ){
// 	    ctxt = 0;
// 	} else {
// 	    if( trapType == Ni_Trap::data_access_exception ){
// 		ctxt = 0; // undefined value
// 	    }
// 	} 
//     } else {
// 	ctxt = tte->context();
//     }


    switch( trapType ){
	case Ni_Trap::fast_data_access_MMU_miss:
	case Ni_Trap::data_access_exception:
	case Ni_Trap::fast_data_access_protection:
	case Ni_Trap::data_real_translation_miss:
	{
	    updateTagRegisters( mmuState_->getdTsbTagTargetPtr(),
				mmuState_->getdTlbTagAccessPtr(),
				ctxt,
				vaddr );
	    mmuState_->setdTsbPs0Pointer( genTsbPointer( vaddr, TSB_PS0_POINTER, ctxt, DATA ) ); 
	    mmuState_->setdTsbPs1Pointer( genTsbPointer( vaddr, TSB_PS1_POINTER, ctxt, DATA ) );  
	}


	if( trapType == Ni_Trap::fast_data_access_protection )
	{
	    int tsbSizePs1;
	    int tsbSizePs0;

	    if(ctxt == 0)
	    {
	        tsbSizePs0 = mmuState_->getdCtxtZeroConfigPtr()->getPS0();
	        tsbSizePs1 = mmuState_->getdCtxtZeroConfigPtr()->getPS1();
	    }
	    else
	    {
	        tsbSizePs0 = mmuState_->getdCtxtNonzeroConfigPtr()->getPS0();
	        tsbSizePs1 = mmuState_->getdCtxtNonzeroConfigPtr()->getPS1();
	    }

    	    if( tte->getSizeIndex() == tsbSizePs1 )
	    {
			// MMU-23 . See Ni_MmuState.cc also

	        mmuState_->isTsbDirectPointerPs0(false);
	    }
	    else
	    {
	        mmuState_->isTsbDirectPointerPs0(true);	
	    }
	    	    
	}

	break;
    }

    throw BasicTrap( trapType, descr );


}

////////////////////////////////////////////////////////////////
Uint64T
Ni_Mmu::genMask( int hi, int lo)
{
    Uint64T hi_mask, lo_mask;

    hi &= 0x3f;
    lo &= 0x3f;

    if( hi < lo )
	return 0;

    hi_mask = 0;

    lo_mask = hi_mask = ~hi_mask;

    hi_mask = hi_mask >> (63 - hi);

    lo_mask = lo_mask << lo;

    return (hi_mask & lo_mask);
}


////////////////////////////////////////////////////////////////
#define I_CNZ_PS0        0
#define I_CNZ_PS1        1
#define I_CZ_PS0         2
#define I_CZ_PS1         3
#define D_CNZ_PS0        4
#define D_CNZ_PS1        5
#define D_CZ_PS0         6
#define D_CZ_PS1         7


VaddrT
Ni_Mmu::genTsbPointer( VaddrT missingVa,  TsbPointerT ps,  ContextT ctxt, MmuTypeT mmutype )
{

    bool   split;  				// = tsbReg->getSPLIT();
    VaddrT tsbBase; 				// = tsbReg->getTSB_BASE() << 13;
    int    tsbSize; 				//= tsbReg->getTSB_SIZE();
    int    pageSizeIdx;
    VaddrT tsbVa;


    int tt;

    tt = 0;
    tt |= (mmutype == DATA)	  << 2;		// 0 == instruction, 1 == data
    tt |= (ctxt == 0)   	  << 1;		// 0 == context 0,   1 == context non-0
    tt |= (ps == TSB_PS1_POINTER) << 0;		// 0 == PS0	     1 == PS1



    switch (tt )
    {

        case I_CNZ_PS0:
	    split = mmuState_->getiCtxtNonzeroTsbBasePs0Ptr()->getSPLIT();
	    tsbSize = mmuState_->getiCtxtNonzeroTsbBasePs0Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getiCtxtNonzeroTsbBasePs0Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getiCtxtNonzeroConfigPtr()->getPS0();
	    break;

        case I_CNZ_PS1:
	    split = mmuState_->getiCtxtNonzeroTsbBasePs1Ptr()->getSPLIT();
	    tsbSize = mmuState_->getiCtxtNonzeroTsbBasePs1Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getiCtxtNonzeroTsbBasePs1Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getiCtxtNonzeroConfigPtr()->getPS1();
	    break;

        case I_CZ_PS0:
	    split = mmuState_->getiCtxtZeroTsbBasePs0Ptr()->getSPLIT();
	    tsbSize = mmuState_->getiCtxtZeroTsbBasePs0Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getiCtxtZeroTsbBasePs0Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getiCtxtZeroConfigPtr()->getPS0();
	    break;

        case I_CZ_PS1:
	    split = mmuState_->getiCtxtZeroTsbBasePs1Ptr()->getSPLIT();
	    tsbSize = mmuState_->getiCtxtZeroTsbBasePs1Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getiCtxtZeroTsbBasePs1Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getiCtxtZeroConfigPtr()->getPS1();
	    break;

        case D_CNZ_PS0:
	    split = mmuState_->getdCtxtNonzeroTsbBasePs0Ptr()->getSPLIT();
	    tsbSize = mmuState_->getdCtxtNonzeroTsbBasePs0Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getdCtxtNonzeroTsbBasePs0Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getdCtxtNonzeroConfigPtr()->getPS0();
	    break;

        case D_CNZ_PS1:
	    split = mmuState_->getdCtxtNonzeroTsbBasePs1Ptr()->getSPLIT();
	    tsbSize = mmuState_->getdCtxtNonzeroTsbBasePs1Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getdCtxtNonzeroTsbBasePs1Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getdCtxtNonzeroConfigPtr()->getPS1();
	    break;

        case D_CZ_PS0:
	    split = mmuState_->getdCtxtZeroTsbBasePs0Ptr()->getSPLIT();
	    tsbSize = mmuState_->getdCtxtZeroTsbBasePs0Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getdCtxtZeroTsbBasePs0Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getdCtxtZeroConfigPtr()->getPS0();
	    break;

        case D_CZ_PS1:
	    split = mmuState_->getdCtxtZeroTsbBasePs1Ptr()->getSPLIT();
	    tsbSize = mmuState_->getdCtxtZeroTsbBasePs1Ptr()->getTSB_SIZE();
	    tsbBase = mmuState_->getdCtxtZeroTsbBasePs1Ptr()->getTSB_BASE();
	    pageSizeIdx = mmuState_->getdCtxtZeroConfigPtr()->getPS1();
	    break;

	default:
	    RIESLING_THROW_DOMAIN_ERROR("FIXME. Ni_Mmu::genTsbPointer");
	    break;

    }

    tsbBase <<= 13;

    if( split == 0 )
    {
	Uint64T a1,a2;

	int baseLoBit = 13+tsbSize;
	int vaHiBit = 21+tsbSize+3*pageSizeIdx;
	int vaLoBit = 13+3*pageSizeIdx;

	a1 = tsbBase & genMask(63, baseLoBit);

	a2 = missingVa & genMask(vaHiBit, vaLoBit);
	a2 = a2 >> (vaLoBit-4);

	tsbVa = a1 | a2;

    }
    else
    {	//split == 1
	Uint64T a1,a2, a3;
	Uint64T ps1 = (ps == TSB_PS1_POINTER ? 1 : 0);

	int baseLoBit = 14+tsbSize;
	int vaHiBit = 21+tsbSize+3*pageSizeIdx;
	int vaLoBit = 13+3*pageSizeIdx;

	a1 = tsbBase & genMask(63, baseLoBit);

	a2 = ps1 << (baseLoBit-1);

	a3 = missingVa & genMask(vaHiBit, vaLoBit);
	a3 = a3 >> (vaLoBit-4);

	tsbVa =	a1 | a2 | a3;
    }

    if( tsbVa &  NI_VA_BIT47 ){
        tsbVa |= (~NI_VA_MASK);
    } else {
        tsbVa &= (NI_VA_MASK);
    }    

    if(pstate_->getAM()){
       tsbVa &= 0x0ffffffffULL;
    }


    return tsbVa;

}

////////////////////////////////////////////////////////////////

void
Ni_Mmu::initTlbs( const std::string &fileName )
{

    RIESLING_THROW_DOMAIN_ERROR(" FixMe. Ni_Mmu::initTlbs() unimplemented");

}

////////////////////////////////////////////////////////////////

PaddrT 
Ni_Mmu::getNewPaddr( PaddrT paddr, bool cacheable ) const
{

    PaddrT new_paddr = paddr & NI_PA_MASK;

    return new_paddr;
}

////////////////////////////////////////////////////////////////

ContextT
Ni_Mmu::getDCtxt( AsiT asi )
{
    ContextT ctxt;
    AsiObject *asiObj = getAsiObject();

    if( asiObj->isPrimaryCtxt( asi )){
	ctxt = mmuState_->getPrimaryDContext();
    } else if( asiObj->isSecondaryCtxt( asi ) ){
	ctxt = mmuState_->getSecondaryContext();
    } else if( asiObj->isNucleusCtxt( asi ) ){
	ctxt = 0;
    } else {
	ostringstream os;
	os << "Don't know how to xlate asi to context for asi = 0x" << hex << (int)asi;
	RIESLING_THROW_DOMAIN_ERROR( os.str() );
    }

    return ctxt;


}

////////////////////////////////////////////////////////////////

ContextT
Ni_Mmu::getICtxt( AsiT asi )
{
    ContextT ctxt;

    if( asi == V9_Asi::ASI_NUCLEUS ){
	ctxt = 0;
    } else if( asi == V9_Asi::ASI_PRIMARY ){
	ctxt = mmuState_->getPrimaryDContext();		// I and D share the same Primary Context reg
    } else {
	RIESLING_THROW_DOMAIN_ERROR( "Don't know how to xlate asi to context" );
    }

    return ctxt;

}


Ni_Mmu::PrivModeT 
Ni_Mmu::checkPrivMode()
{

    if( hpstate_->getENB() == 1 )
    {
        if( pstate_->getPRIV() == 0 && hpstate_->getHPRIV() == 0 )
	{
		return PRIV_USER;
	}
        else if (hpstate_->getHPRIV() == 1)
	{
		return PRIV_HYPER;
	}
	else
	{
		return PRIV_SUPER;
	}
		
    }
    else
    {
	return pstate_->getPRIV() == 1 ? PRIV_SUPERLITE : PRIV_USER;
    }
    
}

bool
Ni_Mmu::isAsiRealToPhysical(AsiT asi)
{
    return
	asi == 0x14 || 
	asi == 0x15 ||
	asi == 0x1C ||
	asi == 0x1D ||
	asi == 0x26 ||
	asi == 0x2e;
}

bool 
Ni_Mmu::checkBypassAsi(Ni_Mmu::PrivModeT p,  AsiT asi)
{
    bool bypassAsi = false;

    switch (p) {
    case PRIV_USER:
	bypassAsi = false;
	if(hpstate_->getENB() == 0x0){
	    switch (asi) {
		case Ni_Asi::ASI_REAL_MEM:
		case Ni_Asi::ASI_REAL_IO:
		case Ni_Asi::ASI_REAL_MEM_LITTLE:
		case Ni_Asi::ASI_REAL_IO_LITTLE:
		case Ni_Asi::ASI_QUAD_LDD_REAL:
		case Ni_Asi::ASI_QUAD_LDD_REAL_LITTLE:
			bypassAsi = true;
		    	break;
	    } 
	}
        break;

    case PRIV_SUPER:
	bypassAsi = false;
        break;

    case PRIV_HYPER:
	switch( asi ) {
	    	case Ni_Asi::ASI_NUCLEUS:
		case Ni_Asi::ASI_NUCLEUS_LITTLE:
		case Ni_Asi::ASI_PRIMARY:
		case Ni_Asi::ASI_SECONDARY:
		case Ni_Asi::ASI_PRIMARY_NO_FAULT:
		case Ni_Asi::ASI_SECONDARY_NO_FAULT:
		case Ni_Asi::ASI_PRIMARY_LITTLE:
		case Ni_Asi::ASI_SECONDARY_LITTLE:
		case Ni_Asi::ASI_PRIMARY_NO_FAULT_LITTLE:
		case Ni_Asi::ASI_SECONDARY_NO_FAULT_LITTLE:

		case Ni_Asi::ASI_QUAD_LDD:
		case Ni_Asi::ASI_NUCLEUS_BLK_INIT_ST_QUAD_LDD:
		case Ni_Asi::ASI_QUAD_LDD_LITTLE:
		case Ni_Asi::ASI_NUCLEUS_BLK_INIT_ST_QUAD_LDD_LITTLE:

		case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_P:
		case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_S:
		case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_P_LITTLE:
		case Ni_Asi::ASI_BLK_INIT_ST_QUAD_LDD_S_LITTLE:
		case Ni_Asi::ASI_BLK_P:
		case Ni_Asi::ASI_BLK_S:
		case Ni_Asi::ASI_BLK_PL:
		case Ni_Asi::ASI_BLK_SL:
    			bypassAsi = true;
	    		break;
	}
	break;

    case PRIV_SUPERLITE:
	switch (asi) {
		case Ni_Asi::ASI_REAL_MEM:
		case Ni_Asi::ASI_REAL_IO:
		case Ni_Asi::ASI_REAL_MEM_LITTLE:
		case Ni_Asi::ASI_REAL_IO_LITTLE:
		case Ni_Asi::ASI_QUAD_LDD_REAL:
		case Ni_Asi::ASI_QUAD_LDD_REAL_LITTLE:
			bypassAsi = true;
		    	break;
	}
	break;

    }
		
    return bypassAsi;

}


void
Ni_Mmu::updateSfsReg( MmuTypeT idSel_, AsiT asi, uint_t faultType, uint8_t isWrite, uint8_t ebit )
{
	Sf_SfsReg	*sfsr;
	AsiObject	*asiObj = getAsiObject();
	bool		updateOW = false;

	if( idSel_ == INSTRUCTION ) {
	    sfsr = mmuState_->getiSfsrPtr();

	    if( initISfsr_ ) {
		sfsr->setFT(0);
	        updateOW = true;
		initISfsr_ = false;
	    }
	}
	else {
	    sfsr = mmuState_->getdSfsrPtr();

	    if( initDSfsr_ ) {
		sfsr->setFT(0);
	        updateOW = true;
		initDSfsr_ = false;
	    }
	}

	sfsr->setASI( asi );

	sfsr->setFT( sfsr->getFT() | faultType );

        sfsr->setE( ebit );

	if( asiObj->isPrimaryCtxt(asi) )
	{
            sfsr->setCT( 0x0 );
        } 
	else if( asiObj->isSecondaryCtxt(asi) )
	{
            if(idSel_ == DATA )
		sfsr->setCT( 0x1 );
	    else
		sfsr->setCT( 0x0 );		
        }
	else if( asiObj->isNucleusCtxt(asi) )
	{
            sfsr->setCT( 0x2 );
        }
	else 
	{
            sfsr->setCT( 0x3 );
        }


					// PR bit is reserved and always reads 0.
					// 7/22/2003
	sfsr->setPR( 0 );

	sfsr->setW( isWrite );

	if( updateOW ) {
	    if( sfsr->getFV() == 1)
            {
	        sfsr->setOW( 1 );
	    }
	    else
	    {
	        sfsr->setOW( 0 );
	    }
	}

	sfsr->setFV( 1 );


	/* internal asi behaviour */
	if(!asiObj->translate(asi)){
	    sfsr->setE( 0x0);
	    sfsr->setCT( 0x3 );
	    sfsr->setFT( sfsr->getFT() & ~(SPEC_LD_FLUSH_TO_EBIT | ILLEGAL_FAULT_OP));
	}
 
}


#define BIT(data, pos)	((data>>pos)&1)

int
Ni_Mmu::genTteDataParity(Uint64T data)
{
				// this is now in Ni_Tlb.cc.
				// keep this here for now just in case the ni
				// might decide to fix the anamaly of parity
				// being inverted in some cases.
				// 10/3/2003

    int p = 0;
    int i;


    for(i = 13; i <=39; i++ ) {
        p += BIT(data, i);			// PA
    }


    for(i = 43; i <=45; i++ ) {
        p += BIT(data, i);			// MUX
    }


    p += BIT(data, 63);				// V

    p += BIT(data, 60);				// NFO

    p += BIT(data, 59);				// IE

    p += BIT(data, 6);				// L

    p += BIT(data, 5);				// CP

    p += BIT(data, 4);				// CV

    p += BIT(data, 3);				// E

    p += BIT(data, 2);				// P

    p += BIT(data, 1);				// W


    return (p & 1);
}

int
Ni_Mmu::genTteTagParity(Uint64T tag)
{
				// this is now in Ni_Tlb.cc.
				// keep this here for now just un case the ni
				// might decide to fix the anamaly of parity
				// being inverted in some cases.
				// 10/3/2003
    int p = 0;
    int i;

    for(i = 61; i <=63; i++ ) {
        p += BIT(tag, i);			// PID
    }

    p += BIT(tag, 60);				// REAL


    for(i = 56; i <=58; i++ ) {
        p += BIT(tag, i);			// MUX
    }


    for(i = 13; i <=47; i++ ) {
        p += BIT(tag, i);			// VA<47:13>
    }


    for(i = 0; i <=12; i++ ) {
        p += BIT(tag, i);			// context
    }

    return (p & 1);
}

Uint64T
Ni_Mmu::encodeTteTagReg( const Ni_Tte *niTte)
{
    Uint64T	data;
    Uint64T 	rbit, pid, mux, parity;

    niTte->getNativeTag( (uint8_t*)&data, sizeof( data ) );

    data = data & ~(0xfULL << 60);		// clear bit 63-60

    rbit = niTte->r() & 0x1;
    pid = niTte->pid() & 0x7;

				// encode special info into the TAG_READ register
    data |= ( pid<<61) | (rbit << 60);

    data = data & ~(0xfULL << 56);		// clear bit 56-59

    mux = niTte->tagMuxSel();
    parity = niTte->tagParity();

    data |= (mux << 56);

    parity &= 1;
    data |= (parity << 59);

    return data;
}

Uint64T
Ni_Mmu::encodeTteDataReg( const Ni_Tte *niTte)
{

    Uint64T	data;
    Uint64T 	mux, parity, used;

    // Note that the EP bit is reserved on N1.
    
    //((Ni_Tte*)niTte)->data4u().setEP(0);    
    niTte->getNativeData( (uint8_t*)&data, sizeof( data ) );

    used = (niTte->used() ? 1 : 0);

    parity = niTte->dataParity();
    mux = niTte->dataMuxSel();

    data = data & ~(0x1fULL << 43);		// clear bits 43-47

    data |= (mux << 43);
    data |= (used << 47);
    data |= (parity << 46);

    return data;

}

void 
Ni_Mmu::setRtlITlbMiss(int i)
{
	rtlITlbMiss = i;
}

void 
Ni_Mmu::setRtlDTlbMiss(int i)
{
	rtlDTlbMiss = i;
}

int
Ni_Mmu::getRtlITlbMiss()
{
	return rtlITlbMiss;
}

int
Ni_Mmu::getRtlDTlbMiss()
{
	return rtlDTlbMiss;
}

void 
Ni_Mmu::setThreadStatus(Ni_ThreadStatusReg *p)
{
	threadstatus_ = p;
}

void
Ni_Mmu::checkTtePageSize(Ni_Tte &tte,  AsiDispatchPacket &p )
{

    if( ! tte.isLegalPageSize() )
    {
        uint_t trapType  = Ni_Trap::data_access_exception;

	updateSfsReg(DATA, p.getAsi(), ILLEGAL_INSTR_VA_ASI, 1, 0);
	mmuState_->setSyncFaultAddress(p.getVaddr());
	updateTagRegisters( mmuState_->getdTsbTagTargetPtr(), mmuState_->getdTlbTagAccessPtr(),	0, p.getVaddr() );
	throw BasicTrap(trapType, "BAD TTE PAGESIZE: data access exception");
    }

}

void
Ni_Mmu::doTlbDataInWrite(MmuTypeT mmutype, AsiDispatchPacket &p)
{
    Uint64T 	data = p.getData();
    Uint32T	pid;
    Uint32T	r_bit = ( (p.getVaddr()>>9) & 1 ) ;	// r-bit is set is bit 9 of Va is set
    Uint32T	isSun4v = ( (p.getVaddr()>>10) & 1 ) ;	// bit10 == 0 => Sun4u, bit10==1 => Sun4v

    Ni_Tlb	*tlb_;
    VaddrT	tagVa;
    ContextT	tagCtxt;

    pid = mmuState_->getidPartitionIdPtr()->getPID();

    if( mmutype == DATA ) {
	tlb_ = dtlb_;
	tagVa = mmuState_->getdTlbTagAccessPtr()->getVA_63_13() << 13;
	tagCtxt = mmuState_->getdTlbTagAccessPtr()->getCONTEXT();
    } else {
	tlb_ = itlb_;
	tagVa = mmuState_->getiTlbTagAccessPtr()->getVA_63_13() << 13;
	tagCtxt = mmuState_->getiTlbTagAccessPtr()->getCONTEXT();
    }

    if( isSun4v) 
    {
        //Ni_TteDataSun4v tteData;
	//tteData.setNative( data );
	dummyTteSun4v.setNative(data);

        //Ni_Tte tte( tagVa, tagCtxt, tteData, r_bit, pid );
	Ni_Tte tte( tagVa, tagCtxt, dummyTteSun4v, r_bit, pid );

    	checkTtePageSize(tte, p);

	tlb_->insert( tte );
    }
    else
    {
	//Ni_TteDataSun4u tteData;
	//tteData.setNative( data );
	dummyTteSun4u.setNative(data);

	//Ni_Tte tte( tagVa, tagCtxt, tteData, r_bit, pid );
	Ni_Tte tte( tagVa, tagCtxt, dummyTteSun4u, r_bit, pid );

	checkTtePageSize(tte, p);

    	tlb_->insert( tte );
    }


}


void
Ni_Mmu::doTlbDataAccessWrite(MmuTypeT mmutype, AsiDispatchPacket &p)
{
    Uint64T 	data = p.getData();
    Uint32T	pid;
    Uint32T	r_bit = ( (p.getVaddr()>>9) & 1 ) ;	// r-bit is set is bit 9 of Va is set
    Uint32T	isSun4v = ( (p.getVaddr()>>10) & 1 ) ;	// bit10 == 0 => Sun4u, bit10==1 => Sun4v

		// TLB entry determined by the replacement policy is written:
		// TAG:  Written with the contents of the tag access register
		// DATA: Written with the store data

    Ni_Tlb	*tlb_;
    VaddrT	tagVa;
    ContextT	tagCtxt;

    pid = mmuState_->getidPartitionIdPtr()->getPID();

    if( mmutype == DATA ) {
	tlb_ = dtlb_;
	tagVa = mmuState_->getdTlbTagAccessPtr()->getVA_63_13() << 13;
	tagCtxt = mmuState_->getdTlbTagAccessPtr()->getCONTEXT();
    } else {
	tlb_ = itlb_;
	tagVa = mmuState_->getiTlbTagAccessPtr()->getVA_63_13() << 13;
	tagCtxt = mmuState_->getiTlbTagAccessPtr()->getCONTEXT();
    }

		// TLB entry specified by the STXA address
		// TAG:  Written with the contents of the tag access register
		// DATA: Written with the store data
    if( isSun4v )
    {
        Ni_TteDataSun4v tteData;
        tteData.setNative( data );
        TtePos pos;
        Ni_Tte tte(  tagVa, tagCtxt, tteData, r_bit, pid );

        pos.tte_ = &tte;
        pos.index_ = getTteIdx( p.getVaddr() );

        checkTtePageSize(tte, p);

        tlb_->insert( pos );

    }
    else
    {
        Ni_TteDataSun4u tteData;
        tteData.setNative( data );
        TtePos pos;
        Ni_Tte tte( tagVa, tagCtxt,tteData, r_bit, pid );

        pos.tte_ = &tte;
        pos.index_ = getTteIdx( p.getVaddr() );

        checkTtePageSize(tte, p);

        tlb_->insert( pos );
    }


}

void 
Ni_Mmu::snapshot( SS_SnapShot &ss, const char *prefix )
{
    char extended_prefix[SS_SnapShot::LINE_SIZE];

    sprintf(ss.tag,"%s.initDSfsr",prefix);	ss.val(&initDSfsr_);
    sprintf(ss.tag,"%s.initISfsr",prefix);	ss.val(&initISfsr_);

    // Ni_Tlb	*itlb_;
    // Ni_Tlb	*dtlb_;
    // Ni_HpstateReg	*hpstate_;
    // V9_PstateReg	*pstate_;
    // Ni_ThreadStatusReg	*threadstatus_;

    // Ni_MmuState *mmuState_;
    sprintf(extended_prefix,"%s.mmuState",prefix);	mmuState_->snapshot(ss, extended_prefix);
    
    // Sf_SharedState *sharedState_;
    
    // std::list<AsiDispatchPacket> i_commitQueue_;
    // std::list<AsiDispatchPacket> d_commitQueue_;

    // int		rtlITlbMiss;
    // int		rtlDTlbMiss;
    // uint64_t cosimDtte_;
    // uint64_t cosimItte_;
}
